#ifndef BASE_VOIP_ENGINE_H_
#define BASE_VOIP_ENGINE_H_

#include "ct_noncopyable.h"
#include "ct_udp_socket.h"
#include "ct_udp_msg_buf.h"
#include "ctRWLock.h"
#include "ct_mutex.h"
#include "AudioCommand.h"
#include <map>
#include <ext/hash_map>

//client address records
//map<userid, user addr>
typedef __gnu_cxx::hash_map<DWORD, struct sockaddr_in > ClientsAddr;
typedef ClientsAddr::iterator CA_IT;
//room users records
//map<roomid, ClientAddr>
typedef std::map<DWORD, ClientsAddr> RoomUsers;
typedef RoomUsers::iterator RU_IT;
//check user wait add list 
//map<userid, roomid>
typedef __gnu_cxx::hash_map<DWORD, DWORD> WaitAddList;
typedef WaitAddList::iterator WAL_IT;
// user speak list
//map<userid, roomid>
typedef __gnu_cxx::hash_map<DWORD, DWORD> SpeakUserList;
typedef SpeakUserList::iterator SUL_IT;

class VOIPEngine:
        private ctNoncopyable
{
        public:
                VOIPEngine()  {}
                ~VOIPEngine() {}
                bool init(const eUDPProtoType type, const std::string &ip, const WORD port);
                void sendData(const void*data, const DWORD size);
                void recvData();
                void sendData();
                struct sockaddr_in *getClientAddr(DWORD userid);
                bool putClientAddr(const DWORD userid, struct sockaddr_in &);
                bool getRoomUsers(DWORD roomid, ClientsAddr &list);
                bool setUserSpeak(const DWORD roomid, const DWORD userid, bool canspeek);       //call by App Server
                bool addUserToEngineWaitList(const DWORD roomid, const DWORD userid);           //call by app server
                bool delUserFromEngineWaitList(const DWORD roomid, const DWORD userid);
                bool isUserInEngineWaitList(const DWORD roomid, const DWORD userid);
                bool delUserFromEngine(const DWORD roomid, const DWORD userid);			//call by app server
                bool addRoom(const DWORD roomid);
                bool delRoom(const DWORD roomid);

                bool putDataToSndQueue(const BYTE *data, const DWORD len);
                bool getDataFromRcvQueue(t_BufferCmdQueue &cmdqueue);

        private:
                bool canUserSpeak(const DWORD roomid, const DWORD userid);
                bool addUserToEngine(DWORD roomid, DWORD userid, struct sockaddr_in clientaddr);
                bool getRoomUsers(DWORD roomid, std::vector<DWORD> &users);
                inline const std::string getServerProtoTypeStr()
                {
                        if (udp_proto_type_ == eUDPProtoType_RTP) {
                                return "RTP";
                        }
                        else if (udp_proto_type_ == eUDPProtoType_RTCP) {
                                return "RTCP";
                        }
                        return "";
                }

        private:
                WORD port_;
                ctUDPSocket udp_socket_;
                eUDPProtoType udp_proto_type_;

                t_BufferCmdQueue rcv_queue_;	//receive buffer queue
                ctMutex rcv_mutex_;
                t_BufferCmdQueue snd_queue_;	//send buffer queue
                ctMutex snd_mutex_;

                RoomUsers room_users_;
                ctRWLock lock_room_users_;

                WaitAddList wait_add_list_;
                ctRWLock wa_lock_;

                SpeakUserList speak_user_list;
                ctRWLock sul_lock_;
};

#endif //BASE_VOIP_ENGINE_H_

